package com.candicom.race;

import com.candicom.race.cars.CarFactory;
import com.candicom.race.cars.CarModel;
import com.candicom.race.gui.MyCanvas;
import com.candicom.race.rings.AbstractRing;
import com.candicom.race.rings.RingFactory;
import com.candicom.race.rings.RingType;
import java.awt.Point;

public class GameEngine {

    private enum GameStatus {

        NULL,
        RUNNING,
        PAUSED;
    }
    private final Controller cont1;
    private final Controller cont2;
    private Player player1 = null;
    private Player player2 = null;
    private AbstractRing ring = null;
    private Thread t = null;
    private MyCanvas canvas = null;
    private boolean loopFlag = false;
    private GameStatus status = GameStatus.NULL;

    public GameEngine() {
        cont1 = new Controller(37, 38, 39, 40);
        cont2 = new Controller(65, 87, 68, 83);
    }

    private void calculatePlayerCondition(Player _p) {

        if(_p.controller.isRight()) {
            _p.car.turnRight();            
        } else if (_p.controller.isLeft()) {
            _p.car.turnLeft();            
        }
 
        if (_p.controller.isBreak()) {
            _p.car.slowDown();
        } else if (_p.controller.isAccelerate()) {
            _p.car.speedUp();
        }

        _p.car.applyForce(ring.getFriction());
        int angle = _p.car.getAngle();
        angle = (90 - angle + 360) % 360;
        double speed = _p.car.getSpeed() / 10.0;
        Point loc = _p.car.getLocation();
        loc.x = (int) (loc.x + (speed * Math.cos(Math.toRadians(angle))));
        loc.y = (int) (loc.y - (speed * Math.sin(Math.toRadians(angle))));
        if (ring.isAvailable(loc)) {
            _p.car.updateLocation(loc);
        } else {
            _p.car.applyForce(ring.getCrashForce());
        }
    }

    private void createThread() {
        t = new Thread() {

            public void run() {

                player1.car.reset();
                player1.car.updateLocation(ring.getStartPoint(1));
                player1.car.updateAngle(ring.getStartAngle());

                player2.car.reset();
                player2.car.updateLocation(ring.getStartPoint(2));
                player2.car.updateAngle(ring.getStartAngle());

                long t1;

                while (loopFlag) {
                    t1 = System.nanoTime();
                    canvas.drawCars(player1.car, player2.car);
                    calculatePlayerCondition(player1);
                    calculatePlayerCondition(player2);
                    System.out.println(player2.car.getSpeed());
                    t1 = 17L - ((System.nanoTime() - t1) / 1000000L);
                    if (t1 > 0) {
                        try {
                            Thread.sleep(t1);
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            }
        };
    }

    public boolean start() {
        if (status == GameStatus.NULL) {
            try {
                if (ring == null) {
                    throw new NullPointerException("Ring cannot be null");
                }
                if (player1 == null) {
                    throw new NullPointerException("Player1 cannot be null");
                }
                if (player2 == null) {
                    throw new NullPointerException("Player2 cannot be null");
                }
                canvas = new MyCanvas(ring.getDimension(), ring.getImage());
                canvas.addKeyListener(cont1);
                canvas.addKeyListener(cont2);
                canvas.setVisible(true);
                createThread();
                loopFlag = true;
                t.start();
                status = GameStatus.RUNNING;
                return true;
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
        }
        return false;
    }

    public void stop() {
        if (status == GameStatus.RUNNING) {
            if (canvas != null) {
                canvas.dispose();
            }
            loopFlag = false;
            t = null;
            canvas = null;
            player1 = null;
            player2 = null;
            ring = null;
            status = GameStatus.NULL;
        }
    }

    public boolean createPlayer1(String _name, CarModel _model) {
        try {
            if (_name == null) {
                throw new NullPointerException("Player1's name cannot be null");
            }
            if (_model == null) {
                throw new NullPointerException("Player1's car model cannot be null");
            }
            player1 = new Player(_name, CarFactory.createACar(_model), cont1);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    public boolean createPlayer2(String _name, CarModel _model) {
        try {
            if (_name == null) {
                throw new NullPointerException("Player2's name cannot be null");
            }
            if (_model == null) {
                throw new NullPointerException("Player2's car model cannot be null");
            }
            player2 = new Player(_name, CarFactory.createACar(_model), cont2);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }

    public boolean createRing(RingType _type) {
        try {
            if (_type == null) {
                throw new NullPointerException("Ring type cannot be null");
            }
            ring = RingFactory.createARing(_type);
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }
}
